package com.huawang.mdesign.model.service.listener;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.list.UnmodifiableList;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.boot.CommandLineRunner;

import java.util.*;

@Slf4j
public class BeanInitMetrics implements BeanPostProcessor, CommandLineRunner {

    private final Map<String, Long> stats = new HashMap<>();

    private final List<Metric> metrics = new ArrayList<>();

    @Override
    public void run(String... args) throws Exception {
        /**
         * 启动完成之后打印时间
         */
        List<Metric> localMetrics = getMetrics();
        ObjectMapper objectMapper = new ObjectMapper();

        log.info("启动完成之后打印时间, {}", objectMapper.writeValueAsString(localMetrics));
    }

    @Override
    public Object postProcessBeforeInitialization(@NotNull Object bean, @NotNull String beanName) throws BeansException {
        stats.put(beanName, System.currentTimeMillis());
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(@NotNull Object bean, @NotNull String beanName) throws BeansException {
        Long start = stats.get(beanName);
        if (start != null) {
            metrics.add(new Metric(beanName, Math.toIntExact(System.currentTimeMillis() - start)));
        }
        return bean;
    }

    public List<Metric> getMetrics() {
        metrics.sort((o1, o2) -> {
            try {
                return o2.getValue() - o1.getValue();
            }catch (Exception e){
                return 0;
            }
        });
        ObjectMapper objectMapper = new ObjectMapper();
        try {
            log.info("metrics {}", objectMapper.writeValueAsString(metrics));
        } catch (JsonProcessingException e) {
            log.error("JsonProcessingException", e);
        }
        return UnmodifiableList.unmodifiableList(metrics);
    }
    @Data
    public static class Metric{
        public Metric(String name, Integer value) {
            this.name = name;
            this.value = value;
            this.createDate = new Date();
        }
        private String name;
        private Integer value;
        private Date createDate;
    }
}

